﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using Bridge.Base.Utilities;
using Pathfinder.Base.Constructs;

namespace Pathfinder.Base.Importer
{
    public static class DefenseStatblockImporter
    {
        /// <summary>
        /// Finds the AC types in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <returns>Dictionary of ACTypes found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static Dictionary<ACType, int> FindAC(string input)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindAC(input, ACBlockRegex, ACTypeBlockRegex);
        }

        /// <summary>
        /// Finds the AC types in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="acBlockRegex">Initial Regex to search the statblock.</param>
        /// <param name="acTypeBlockRegex">Secondary regex to search on the found above. If null or empty, ignored.</param>
        /// <returns>Dictionary of ACTypes found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static Dictionary<ACType, int> FindAC(string input, string acBlockRegex, string acTypeBlockRegex)
        {
            input.ThrowIfNullOrEmpty("input");
            acBlockRegex.ThrowIfNullOrEmpty("acBlockRegex");

            string acBlock = input.FindFirstMatch(acBlockRegex);
            string acTypeBlock = string.IsNullOrEmpty(acBlock) ? null : (string.IsNullOrEmpty(acTypeBlockRegex) ? acBlock : acBlock.FindFirstMatch(acTypeBlockRegex));
            if (acTypeBlock != null)
            {
                Dictionary<ACType, int> acTypeList = new Dictionary<ACType, int>();
                foreach (string acType in acTypeBlock.Split(','))
                {
                    ACType actualType;

                    if (acType.Trim().Split(' ')[1].TryGetEnumValue<ACType>(out actualType))
                    {
                        int acAmount = int.Parse(acType.FindFirstMatch(@"\d+")) * (acType.Trim().StartsWith("+") ? 1 : -1);
                        if (acTypeList.ContainsKey(actualType))
                        {
                            acTypeList[actualType] = acAmount;
                        }
                        else
                        {
                            acTypeList.Add(actualType, acAmount);
                        }
                    }
                }
                return acTypeList;
            }
            return null;
        }

        /// <summary>
        /// Finds the Base HP in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <returns>Base HP found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static int? FindBaseHP(string input)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindBaseHP(input, HPRegex);
        }

        /// <summary>
        /// Finds the Base HP in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="acBlockRegex">Initial Regex to search the statblock.</param>
        /// <param name="acTypeBlockRegex">Secondary regex to search on the found above. If null or empty, ignored.</param>
        /// <returns>Base HP found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static int? FindBaseHP(string input, string hpRegex)
        {
            input.ThrowIfNullOrEmpty("input");
            hpRegex.ThrowIfNullOrEmpty("hpRegex");

            string hp = input.FindLastMatch(hpRegex);
            if (hp != null)
            {
                return int.Parse(hp);
            }
            return null;
        }

        /// <summary>
        /// Finds the Max HP in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="acBlockRegex">Initial Regex to search the statblock.</param>
        /// <param name="acTypeBlockRegex">Secondary regex to search on the found above. If null or empty, ignored.</param>
        /// <returns>Dictionary of ACTypes found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static int? FindMaxHP(string input)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindMaxHP(input, HPRegex);
        }

        /// <summary>
        /// Finds the Max HP in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="hpRegex">Initial Regex to search the statblock.</param>
        /// <returns>Max HP found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static int? FindMaxHP(string input, string hpRegex)
        {
            input.ThrowIfNullOrEmpty("input");
            hpRegex.ThrowIfNullOrEmpty("hpRegex");

            string hp = input.FindFirstMatch(hpRegex);
            if (hp != null)
            {
                return int.Parse(hp);
            }
            return null;
        }

        /// <summary>
        /// Finds the Current HP in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <returns>Current HP found, or Max HP. Null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static int? FindCurrentHP(string input)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindCurrentHP(input, CurrentHPRegex, AlternateCurrentHPRegex, InnerCurrentHPRegex, HPRegex);
        }

        /// <summary>
        /// Finds the Current HP in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="hpRegex">Regex to pass to FindMaxHP if HD is not found correctly.</param>
        /// <returns>Current HP found, or Max HP. Null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static int? FindCurrentHP(string input, string hpRegex)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindCurrentHP(input, CurrentHPRegex, AlternateCurrentHPRegex, InnerCurrentHPRegex, hpRegex);
        }

        /// <summary>
        /// Finds the Current HP in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="currentHpRegex">Initial Regex to search the statblock.</param>
        /// <param name="alternateCurrentHpRegex">Secondary regex to search if above is not found. If null or empty, ignored.</param>
        /// <param name="innerCurrentHpRegex">Current Hp regex to search on the above found information.</param>
        /// <param name="hpRegex">Regex to pass to FindMaxHP if HD is not found correctly.</param>
        /// <returns>Current HP found, or Max HP. Null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static int? FindCurrentHP(string input, string currentHpRegex, string alternateCurrentHpRegex, string innerCurrentHpRegex, string hpRegex)
        {
            input.ThrowIfNullOrEmpty("input");
            currentHpRegex.ThrowIfNullOrEmpty("currentHpRegex");
            innerCurrentHpRegex.ThrowIfNullOrEmpty("innerCurrentHpRegex");

            string hp = input.FindFirstMatch(currentHpRegex) ?? (string.IsNullOrEmpty(alternateCurrentHpRegex) ? null : input.FindFirstMatch(alternateCurrentHpRegex));
            if (hp != null)
            {
                hp = hp.FindFirstMatch(innerCurrentHpRegex).FindFirstMatch(@"\d+");
                return int.Parse(hp);
            }
            if (!string.IsNullOrEmpty(hpRegex))
            {
                return FindMaxHP(input, hpRegex);
            }
            return FindMaxHP(input);
        }

        /// <summary>
        /// Finds the HD in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <returns>Dictionary of HD found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static Dictionary<int, int> FindHD(string input)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindHD(input, HDRegex);
        }

        /// <summary>
        /// Finds the HD in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="hdRegex">Regex to search the statblock.</param>
        /// <returns>Dictionary of HD found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input or hdRegex is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input or hdRegex is empty.</exception>
        public static Dictionary<int, int> FindHD(string input, string hdRegex)
        {
            input.ThrowIfNullOrEmpty("input");
            hdRegex.ThrowIfNullOrEmpty("hdRegex");

            string hd = input.FindFirstMatch(hdRegex);
            if (hd != null)
            {
                StringCollection allHd = hd.FindAllMatches(@"\d+d\d+");
                Dictionary<int, int> hdCollection = new Dictionary<int, int>();
                foreach (string hdString in allHd)
                {
                    int numberHd = int.Parse(hdString.FindFirstMatch(@"\d+"));
                    int hdNumber = int.Parse(hdString.FindLastMatch(@"\d+"));
                    if (hdCollection.ContainsKey(hdNumber))
                    {
                        hdCollection[hdNumber] += numberHd;
                    }
                    else
                    {
                        hdCollection.Add(hdNumber, numberHd);
                    }
                }
                return hdCollection;
            }
            return null;
        }

        /// <summary>
        /// Finds the Saves in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="isBase">If true, will return base saves (use FindLastMatch); otherwise will return total saves (use FindFirstMatch)</param>
        /// <returns>Dictionary of Saves found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static Dictionary<SaveType, int> FindSaves(string input, bool isBase)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindSaves(input, isBase, SaveRegex);
        }

        /// <summary>
        /// Finds the Saves in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="isBase">If true, will return base saves (use FindLastMatch); otherwise will return total saves (use FindFirstMatch)</param>
        /// <param name="regex">Regex to use</param>
        /// <returns>Dictionary of Saves found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input or regex is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input or regex is empty.</exception>
        public static Dictionary<SaveType, int> FindSaves(string input, bool isBase, string regex)
        {
            input.ThrowIfNullOrEmpty("input");
            regex.ThrowIfNullOrEmpty("regex");

            Dictionary<SaveType, int> saves = new Dictionary<SaveType, int>();
            saves.Add(SaveType.Fort, 0);
            saves.Add(SaveType.Ref, 0);
            saves.Add(SaveType.Will, 0);
            foreach (SaveType saveType in Enum.GetValues(typeof(SaveType)))
            {
                string save = isBase ? input.FindLastMatch(string.Format(regex, saveType)) : input.FindFirstMatch(string.Format(regex, saveType));
                if (save != null)
                {
                    saves[saveType] = int.Parse(save.FindFirstMatch(@"\d+")) * (save.StartsWith("+") ? 1 : -1);
                }
            }
            return saves;
        }

        /// <summary>
        /// Finds the Damage Resistance in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <returns>Dictionary of Damage Resistances found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static Dictionary<DRType, int> FindDR(string input)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindDR(input, DRRegex);
        }

        /// <summary>
        /// Finds the Damage Resistance in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="regex">Regex to use</param>
        /// <returns>Dictionary of Damage Resistances found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input or regex is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input or regex is empty.</exception>
        public static Dictionary<DRType, int> FindDR(string input, string regex)
        {
            input.ThrowIfNullOrEmpty("input");
            regex.ThrowIfNullOrEmpty("regex");

            string dr = input.FindFirstMatch(regex);
            if (dr != null)
            {
                Dictionary<DRType, int> drTypes = new Dictionary<DRType, int>();
                int drAmount = int.Parse(dr.FindFirstMatch(@"\d+"));
                foreach (DRType drType in Enum.GetValues(typeof(DRType)))
                {
                    if (dr.ToLower().Contains(drType.ToString().Replace('_', ' ').ToLower()))
                    {
                        drTypes.Add(drType, drAmount);
                    }
                }
                return drTypes;
            }
            return null;
        }

        /// <summary>
        /// Finds the Immunities in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <returns>Dictionary of Immunities found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static List<ImmunityType> FindImmunities(string input)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindImmunities(input, ImmunityRegex);
        }

        /// <summary>
        /// Finds the Immunities in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="regex">Regex to use</param>
        /// <returns>Dictionary of Immunities found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input or regex is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input or regex is empty.</exception>
        public static List<ImmunityType> FindImmunities(string input, string regex)
        {
            input.ThrowIfNullOrEmpty("input");
            regex.ThrowIfNullOrEmpty("regex");

            string immunities = input.FindFirstMatch(regex);

            if (immunities != null)
            {
                List<ImmunityType> immunityTypes = new List<ImmunityType>();

                foreach (string immunity in immunities.Split(','))
                {
                    ImmunityType immunityType;
                    if (immunity.Trim().Replace(' ', '_').TryGetEnumValue<ImmunityType>(out immunityType) && !immunityTypes.Contains((ImmunityType)immunityType))
                    {
                        immunityTypes.Add((ImmunityType)immunityType);
                    }
                }
                return immunityTypes;
            }
            return null;
        }

        /// <summary>
        /// Finds the Energy Resistance in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <returns>Dictionary of Energy Resistance found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static Dictionary<ERType, int> FindER(string input)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindER(input, ERRegex);
        }

        /// <summary>
        /// Finds the Energy Resistance in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="regex">Regex to use</param>
        /// <returns>Dictionary of Energy Resistance found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input or regex is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input or regex is empty.</exception>
        public static Dictionary<ERType, int> FindER(string input, string regex)
        {
            input.ThrowIfNullOrEmpty("input");
            regex.ThrowIfNullOrEmpty("regex");

            StringCollection ers = input.FindAllMatches(regex) ?? new StringCollection();
            string er = null;
            foreach (string erTest in ers)
            {
                if (!erTest.StartsWith("energy"))
                {
                    er = erTest;
                }
            }
            if (er != null)
            {
                Dictionary<ERType, int> erTypes = new Dictionary<ERType, int>();
                foreach (string resist in er.Split(','))
                {
                    char splitChar = ' ';

                    string actualResist = resist.FindFirstMatch(@"\w+ \d+");
                    if (actualResist == null)
                    {
                        actualResist = resist.FindFirstMatch(@"\w+/\d+");
                        splitChar = '/';
                    }
                    if (actualResist != null)
                    {
                        ERType erType;

                        if (actualResist.Split(splitChar)[0].TryGetEnumValue<ERType>(out erType))
                        {
                            erTypes.Add((ERType)erType, int.Parse(actualResist.Split(splitChar)[1]));
                        }
                    }
                }
                return erTypes;
            }
            return null;
        }

        /// <summary>
        /// Finds the Defensive Abilities in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <returns>Defensive abilities found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static string FindDefensiveAbilities(string input)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindDefensiveAbilities(input, DefensiveAbilitiesRegex);
        }

        /// <summary>
        /// Finds the Defensive Abilities in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="regex">Regex to use</param>
        /// <returns>Defensive abilities found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input or regex is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input or regex is empty.</exception>
        public static string FindDefensiveAbilities(string input, string regex)
        {
            input.ThrowIfNullOrEmpty("input");
            regex.ThrowIfNullOrEmpty("regex");

            return input.FindFirstMatch(regex);
        }

        /// <summary>
        /// Finds the SR in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <returns>SR found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static int? FindSR(string input)
        {
            return FindSR(input, SRRegex);
        }

        /// <summary>
        /// Finds the SR in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="regex">Regex to use</param>
        /// <returns>SR found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input or regex is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input or regex is empty.</exception>
        public static int? FindSR(string input, string regex)
        {
            string sr = input.FindFirstMatch(regex);
            if (sr != null)
            {
                return int.Parse(sr);
            }
            return null;
        }

        /// <summary>
        /// Finds the Bonus HP in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <returns>BonusHP found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public static int? FindBonusHP(string input)
        {
            input.ThrowIfNullOrEmpty("input");

            return FindBonusHP(input, BonusHPHPInfoRegex);
        }

        /// <summary>
        /// Finds the Bonus HP in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="hdInfoRegex">Regex to use for hdInfo.</param>
        /// <param name="hpInfoRegex">Regex to use for hpInfo.</param>
        /// <returns>BonusHP found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input, bonusHP, hdInfo, or hpInfo is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input, bonusHP, hdInfo, or hpInfo is empty.</exception>
        public static int? FindBonusHP(string input, string hpInfoRegex)
        {
            input.ThrowIfNullOrEmpty("input");
            hpInfoRegex.ThrowIfNullOrEmpty("hpInfoRegex");

            return FindBonusHP(input, hpInfoRegex, BonusHPHDInfoRegex);
        }

        /// <summary>
        /// Finds the Bonus HP in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="hdInfoRegex">Regex to use for hdInfo.</param>
        /// <param name="hpInfoRegex">Regex to use for hpInfo.</param>
        /// <returns>BonusHP found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input, bonusHP, or hpInfo is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input, bonusHP, or hpInfo is empty.</exception>
        public static int? FindBonusHP(string input, string hpInfoRegex, string hdInfoRegex)
        {
            input.ThrowIfNullOrEmpty("input");
            hpInfoRegex.ThrowIfNullOrEmpty("hpInfoRegex");
            hdInfoRegex.ThrowIfNullOrEmpty("hdInfoRegex");

            return FindBonusHP(input, hpInfoRegex, hdInfoRegex, BonusHPRegex);
        }

        /// <summary>
        /// Finds the Bonus HP in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="bonusHpRegex">Regex to use for bonusHP.</param>
        /// <param name="hdInfoRegex">Regex to use for hdInfo.</param>
        /// <param name="hpInfoRegex">Regex to use for hpInfo.</param>
        /// <returns>BonusHP found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input, bonusHP, hdInfo, or hpInfo is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input, bonusHP, hdInfo, or hpInfo is empty.</exception>
        public static int? FindBonusHP(string input, string hpInfoRegex, string hdInfoRegex, string bonusHpRegex)
        {
            input.ThrowIfNullOrEmpty("input");
            hpInfoRegex.ThrowIfNullOrEmpty("hpInfoRegex");
            hdInfoRegex.ThrowIfNullOrEmpty("hdInfoRegex");
            bonusHpRegex.ThrowIfNullOrEmpty("bonusHpRegex");

            string hpInfo = input.FindFirstMatch(hpInfoRegex);
            if (hpInfo != null)
            {
                string hdInfo = input.FindFirstMatch(hdInfoRegex);
                if (hdInfo != null)
                {
                    string bonusHP = input.FindFirstMatch(bonusHpRegex);
                    if (bonusHP != null)
                    {
                        return int.Parse(bonusHP);
                    }
                }
            }
            return null;
        }

        private const string ACBlockRegex = "AC .+?hp";
        private const string ACTypeBlockRegex = @"(?<=\().+?(?=\))";
        private const string HPRegex = @"(?<=hp )\d+";
        private const string CurrentHPRegex = @"hp \d+ \(currently \d+";
        private const string AlternateCurrentHPRegex = @"hp \d+ \(\d+ currently";
        private const string InnerCurrentHPRegex = @"(?<=\().*?\d+";
        private const string HDRegex = @"hp \d+ \(.+?\)";
        private const string SaveRegex = @"(?<={0} )[\+-]\d+";
        private const string DRRegex = @"(?<=DR ).+?((?=;)|(?=OFFENSE))";
        private const string ImmunityRegex = @"(?<=Immune ).+?((?=Resist)|(?=SR)|(?=;)|(?=OFFENSE))";
        private const string ERRegex = "(?<=Resist ).+?((?=OFFENSE)|(?=;))";
        private const string DefensiveAbilitiesRegex = @"(?<=Defensive Abilities ).+?((?=DR)|(?=Immune)|(?=Resist)|(?=SR)|(?=OFFENSE))";
        private const string SRRegex = @"(?<=SR )\d+";
        private const string BonusHPHPInfoRegex = @"hp.+?\(.+?\)";
        private const string BonusHPHDInfoRegex = @"(?<=\().+?(?=\))";
        private const string BonusHPRegex = @"(?<=\+)\d+";

    }
}
